﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Documents;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Windows.Input;

namespace Chaos.drag
{
    class manager : ContentControl
    {
        public manager()
        {
        }
 
        drag.adorner _adorner = null;
        public FrameworkElement DragScope
        {
            get { return this.Content as FrameworkElement; }
        }

        public void ExecuteDrag(UIElement uielement, MouseEventArgs e)
        {
            try
            {
                Console.WriteLine("Started dragging");

                // We enable Drag & Drop in our scope ...  We are not implementing Drop, so it is OK, but this allows us to get DragOver 
                bool previousDrop = DragScope.AllowDrop;
                DragScope.AllowDrop = true;

                // The DragOver event ... 
                DragEventHandler draghandler = new DragEventHandler(DragScope_DragOver);
                this.PreviewDragOver += draghandler;

                // Drag Leave is optional, but write up explains why I like it .. 
                DragEventHandler dragleavehandler = new DragEventHandler(DragScope_DragLeave);
                this.DragLeave += dragleavehandler;

                // QueryContinue Drag goes with drag leave... 
                QueryContinueDragEventHandler queryhandler = new QueryContinueDragEventHandler(DragScope_QueryContinueDrag);
                this.QueryContinueDrag += queryhandler;

                //Here we create our adorner.. 
                _adorner = new drag.adorner(uielement);
                _adorner.XOrigin = e.GetPosition(DragScope).X;
                _adorner.YOrigin = e.GetPosition(DragScope).Y;

                AdornerLayer.GetAdornerLayer(DragScope as Visual).Add(_adorner);         
                _dragHasLeftScope = false;

                //Finally lets drag drop 
                //DataObject data = new DataObject(System.Windows.DataFormats.Text.ToString(), "abcd");
                DragDropEffects de = DragDrop.DoDragDrop(uielement, uielement, DragDropEffects.Move);

                // Clean up our mess :) 
                DragScope.AllowDrop = previousDrop;
                AdornerLayer.GetAdornerLayer(DragScope).Remove(_adorner);
                _adorner = null;

                DragScope.DragLeave -= dragleavehandler;
                DragScope.QueryContinueDrag -= queryhandler;
                DragScope.PreviewDragOver -= draghandler;

                Console.WriteLine("Stopped dragging");
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        private bool _dragHasLeftScope = false;
        void DragScope_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
        {
            if (this._dragHasLeftScope)
            {
                Console.WriteLine("Cancel dragging");
                e.Action = DragAction.Cancel;
                e.Handled = true;
            }

        }
        void DragScope_DragLeave(object sender, DragEventArgs e)
        {
            if (e.OriginalSource == DragScope)
            {
                Point p = e.GetPosition(DragScope);
                Rect r = VisualTreeHelper.GetContentBounds(DragScope);
                if (!r.Contains(p))
                {
                    Console.WriteLine("DragLeave");
                    this._dragHasLeftScope = true;
                    e.Handled = true;
                }
            }
        }

        void DragScope_DragOver(object sender, DragEventArgs args)
        {
            System.Windows.UIElement uielement = sender as System.Windows.UIElement;
            if (_adorner != null)
            {
                Console.WriteLine("DragOver + " + args.GetPosition(uielement));
                _adorner.LeftOffset = args.GetPosition(DragScope).X;
                _adorner.TopOffset = args.GetPosition(DragScope).Y;
            }
        }
    } 
}
